#include "Chess.h"
#include <iostream>

//校验位置是否合法
bool isInBoard(int index);
bool isValidRKingRGuardPosition(int index);
bool isValidRELEPHANTPosition(int index);
bool isValidBKingBGuardPosition(int index);
bool isValidBELEPHANTPosition(int index);


Chess::Chess()
{
	this->board[getIndex(4, 9)] = R_KING;

	this->board[getIndex(1, 7)] = R_CANNON;
	this->board[getIndex(7, 7)] = R_CANNON;

	this->board[getIndex(0, 9)] = R_CAR;
	this->board[getIndex(8, 9)] = R_CAR;

	this->board[getIndex(2, 9)] = R_ELEPHANT;
	this->board[getIndex(6, 9)] = R_ELEPHANT;

	this->board[getIndex(3, 9)] = R_GUARD;
	this->board[getIndex(5, 9)] = R_GUARD;

	this->board[getIndex(1, 9)] = R_HORSE;
	this->board[getIndex(7, 9)] = R_HORSE;

	this->board[getIndex(0, 6)] = R_SOLDIER;
	this->board[getIndex(2, 6)] = R_SOLDIER;
	this->board[getIndex(4, 6)] = R_SOLDIER;
	this->board[getIndex(6, 6)] = R_SOLDIER;
	this->board[getIndex(8, 6)] = R_SOLDIER;


	this->board[getIndex(4, 0)] = B_KING;

	this->board[getIndex(1, 2)] = B_CANNON;
	this->board[getIndex(7, 2)] = B_CANNON;

	this->board[getIndex(0, 0)] = B_CAR;
	this->board[getIndex(8, 0)] = B_CAR;
	
	this->board[getIndex(2, 0)] = B_ELEPHANT;
	this->board[getIndex(6, 0)] = B_ELEPHANT;
	
	this->board[getIndex(3, 0)] = B_GUARD;
	this->board[getIndex(5, 0)] = B_GUARD;
	
	this->board[getIndex(1, 0)] = B_HORSE;
	this->board[getIndex(7, 0)] = B_HORSE;

	this->board[getIndex(0, 3)] = B_SOLDIER;
	this->board[getIndex(2, 3)] = B_SOLDIER;
	this->board[getIndex(4, 3)] = B_SOLDIER;
	this->board[getIndex(6, 3)] = B_SOLDIER;
	this->board[getIndex(8, 3)] = B_SOLDIER;

	for (int i = 0; i < 200; i++)
	{
		historyPool.push(new History());
	}

}

Chess::Chess(bool firstPlay): Chess::Chess()
{
	this->nowPlayer = firstPlay;
}

short Chess::getState()
{
	return this->state;
}

void Chess::setState(short i)
{
	this->state = i;
	return;
}

void Chess::addToValidMove(int fromIndex, int toIndex, bool (*isValidPosition)(int))
{
	if (!isValidPosition(toIndex) || this->indexHaveSelf(toIndex, this->board[fromIndex])) return;

	this->validMoves.push(indexIndex(fromIndex, toIndex));
	
}

void Chess::addToValidMove(int fromIndex, int toIndex)
{
	if (this->indexHaveSelf(toIndex, this->board[fromIndex])) return;
	

	this->validMoves.push(indexIndex(fromIndex,toIndex));
	
}

bool trueFun(int x, int y)
{
	return true;
}

Stack_list<int, 250> Chess::getValidMoves(bool side)
{

	this->validMoves.setNull();
	for (int i = 0; i < 130; i++)
	{

		//如果和要获取走法的棋子颜色不一样就跳过
		if (this->board[i] / 10 == side) continue;
		switch (this->board[i])
		{
		case NO_PIECE:
			continue;
		case R_CANNON:
			[[fallthrough]];
		case B_CANNON:
		{
			//向一个方向寻找， 遇到棋子之前的位置可以到达，遇到棋子后第一个棋子如果是红色的可以到达，之后i++在向另一个方向寻找
			//j控制向上向下还是向左向右找，0上 1下 2左 3右
			int index = 0;
			for (int j = 0; j < 4; j++)//循环4次，每次往一个方向找
			{
				bool meetPiece = false;
				index = i;//一开始先以自己的位置作为起始位置
				while (true)
				{
					//向上移动
					if (j == 0) index -= 13;
					//向下
					else if (j == 1) index += 13;
					//向左
					else if (j == 2) index -= 1;
					//向右
					else if (j == 3) index += 1;

					//如果nowXY在棋盘外边就判断下一个方向
					if (!isInBoard(index)) break;

					//如果还未遇到棋子
					if (!meetPiece)
					{
						//遇到了棋子就把遇到棋子设true
						if (this->board[index])
						{
							meetPiece = true;
							continue;
						}
						//没遇到就添加到可到达集合
						else
						{
							this->validMoves.push(1000 * i + index);
						}
					}
					else
					{
						//遇到棋子判断颜色，不一样就能到达，一样就不能
						if (this->board[index])
						{
							this->addToValidMove(i, index);

							//判断这个方向结束，判断下一个方向
							break;
						}
					}

				}
			}

			break;
		}
		case R_CAR:
			[[fallthrough]];
		case B_CAR:
		{
			int index = 0;
			for (int j = 0; j < 4; j++)//i控制向上向下还是向左向右找，0上 1下 2左 3右
			{
				index = i;

				while (true)
				{
					//向上移动
					if (j == 0) index -= 13;
					//向下
					else if (j == 1) index += 13;
					//向左
					else if (j == 2) index -= 1;
					//向右
					else if (j == 3) index += 1;

					//如果出界了就停止循环
					if (!isInBoard(index)) break;

					if (this->board[index])//如果这个地方有棋子
					{
						this->addToValidMove(i, index);

						break;
					}
					//加到能走的地方
					this->validMoves.push(indexIndex(i,index));
				}
			}
			break;
		}
		case R_HORSE:
			[[fallthrough]];
		case B_HORSE:
			if (!this->board[i - 13])
			{
				addToValidMove(i, i - 27, isInBoard);
				addToValidMove(i, i - 25, isInBoard);
			}
			if (!this->board[i - 1])
			{
				addToValidMove(i, i - 15, isInBoard);
				addToValidMove(i, i + 11, isInBoard);
			}
			if (!this->board[i + 13])
			{
				addToValidMove(i, i + 25, isInBoard);
				addToValidMove(i, i + 27, isInBoard);
			}
			if (!this->board[i + 1])
			{
				addToValidMove(i, i - 11, isInBoard);
				addToValidMove(i, i + 15, isInBoard);
			}
			
			break;
		case R_KING:
			addToValidMove(i, i - 13, &isValidRKingRGuardPosition);
			addToValidMove(i, i + 13, &isValidRKingRGuardPosition);
			addToValidMove(i, i - 1, &isValidRKingRGuardPosition);
			addToValidMove(i, i + 1, &isValidRKingRGuardPosition);
			break;
		case R_ELEPHANT:
			if (!this->board[i - 14]) this->addToValidMove(i, i - 28, isValidRELEPHANTPosition);
			if (!this->board[i - 12]) this->addToValidMove(i, i - 24, isValidRELEPHANTPosition);
			if (!this->board[i + 12]) this->addToValidMove(i, i + 24, isValidRELEPHANTPosition);
			if (!this->board[i + 14]) this->addToValidMove(i, i + 28, isValidRELEPHANTPosition);
			break;
		case R_GUARD:
			addToValidMove(i, i - 12, isValidRKingRGuardPosition);
			addToValidMove(i, i - 14, isValidRKingRGuardPosition);
			addToValidMove(i, i + 14, isValidRKingRGuardPosition);
			addToValidMove(i, i + 12, isValidRKingRGuardPosition);
			break;
		
		case R_SOLDIER:
			if (getY(i) <= 4)
			{
				addToValidMove(i, i - 1, isInBoard);
				addToValidMove(i, i + 1, isInBoard);
			}
			addToValidMove(i, i - 13, isInBoard);
			break;

		case B_KING:
			addToValidMove(i, i - 13, isValidBKingBGuardPosition);
			addToValidMove(i, i + 13, isValidBKingBGuardPosition);
			addToValidMove(i, i - 1, isValidBKingBGuardPosition);
			addToValidMove(i, i + 1, isValidBKingBGuardPosition);
			break;
		case B_ELEPHANT:
			if (!this->board[i - 14]) this->addToValidMove(i, i - 28, isValidBELEPHANTPosition);
			if (!this->board[i - 12]) this->addToValidMove(i, i - 24, isValidBELEPHANTPosition);
			if (!this->board[i + 12]) this->addToValidMove(i, i + 24, isValidBELEPHANTPosition);
			if (!this->board[i + 14]) this->addToValidMove(i, i + 28, isValidBELEPHANTPosition);
			break;
		case B_GUARD:
			addToValidMove(i, i - 12, isValidBKingBGuardPosition);
			addToValidMove(i, i - 14, isValidBKingBGuardPosition);
			addToValidMove(i, i + 14, isValidBKingBGuardPosition);
			addToValidMove(i, i + 12, isValidBKingBGuardPosition);
			break;
		case B_SOLDIER:
			if (getY(i) >= 5)
			{
				addToValidMove(i, i - 1, isInBoard);
				addToValidMove(i, i + 1, isInBoard);
			}
			addToValidMove(i, i + 13, isInBoard);

			break;

		}

	}
	return this->validMoves;
}


bool Chess::indexHaveSelf(short index, short piece)
{
	return this->board[index] && this->board[index] / 10 == piece / 10;
}

bool Chess::indexHaveEnemy(short index, short piece)
{
	return this->board[index] && this->board[index] / 10 != piece / 10;
}

bool Chess::indexHavePiece(const int index)
{
	return this->board[index];
}

bool Chess::xyHavePiece(int x, int y)
{
	return this->indexHavePiece(getIndex(x, y));
}

void Chess::move(int fromX, int fromY, int toX, int toY)
{
	move(indexIndex(getIndex(fromX, fromY), getIndex(toX, toY)));
}
void Chess::move(int indexIndex)
{
	//创建一条移动记录,并让他的下一个是之前的第一个，然后把他变成第一个
	//History* nowMove = new History(this->pieceArry[toY][toX], fromX * 1000 + fromY * 100 + toX * 10 + toY, this->previousMove);
	History* nowMove = this->historyPool.pop()->init(this->board[toIndex(indexIndex)], indexIndex, this->previousMove);
	this->previousMove = nowMove;

	//如果移动的目标位置是红将或黑将的话就把kingState设置成红或黑死
	if (this->board[toIndex(indexIndex)] == R_KING) this->kingState = NO_R_KING;
	else if (this->board[toIndex(indexIndex)] == B_KING) this->kingState = NO_B_KING;

	//直接进行移动
	this->board[toIndex(indexIndex)] = this->board[fromIndex(indexIndex)];
	this->board[fromIndex(indexIndex)] = NO_PIECE;
	//执子的玩家变成另一方
	this->nowPlayer = !this->nowPlayer;
	
}

bool Chess::rollBack()
{
	//如果上一步没有的话就返回false
	if (!this->previousMove) return false;

	//移动回去
	this->board[fromIndex(this->previousMove->indexIndex)] = this->board[toIndex(this->previousMove->indexIndex)];
	//把吃的子复活
	this->board[toIndex(this->previousMove->indexIndex)] = this->previousMove->diedPiece;

	//执子的玩家转变
	this->nowPlayer = !this->nowPlayer;

	History* temp = this->previousMove;
	//将上一步指向上上一步
	this->previousMove = this->previousMove->previous;

	//置空之后放回池子
	temp->setNull();
	this->historyPool.push(temp);

	this->kingState = RB_KING_ALL_HAVE;



	return true;
}

short Chess::getPiece(int x, int y)
{
	return this->board[getIndex(x, y)];
}

short Chess::getIndexPiece(int index)
{
	return this->board[index];
}

bool Chess::getNowPlayer()
{
	return this->nowPlayer;
}

int Chess::getKingState()
{
	return this->kingState;
}

void Chess::forBoard(void fun(int range, short piece))
{
	for (int i = 0; i < 130; i++) fun(i, this->board[i]);
}

bool Chess::isInCheck(bool side)
{
	int kingX = 0;
	int kingY = 0;
	//for (int i)
	//for (int i = 0; i < 130; i++)
	//{
	//	if ((this->board[i] / 10)  ==  !side)
	//}
	return false;
}

bool Chess::canMove(int fromX, int fromY, int toX, int toY)
{
	//如果对应位置无棋子返回false
	if (!this->indexHavePiece(getIndex(fromX, fromY))) return false;


	int indexIndex_a = indexIndex(getIndex(fromX, fromY), getIndex(toX, toY));
	
	Stack_list<int, 250> tempValidMoves;

	//判断要移动的棋子是什么颜色，获取对应颜色的所有棋子的走法列表
	if (this->getIndexPiece(getIndex(fromX, fromY)) / 10 == 1) tempValidMoves = this->getValidMoves(false);
	else tempValidMoves = this->getValidMoves(true);

	for (int i = 0; i < tempValidMoves.size(); i++)
	{
		if (tempValidMoves.geti(i) == indexIndex(getIndex(fromX, fromY), getIndex(toX, toY)))return true;
	}
	return false;
}

int Chess::getTotalValue(bool side)
{

	int totalValue = 0;

	for (int i = 0; i < 130; i++)
	{
		//如果这个位置没有棋子就跳过
		if (!this->board[i]) continue;

		//总价值加上这个棋子的存活价值
		//总价值加上这个棋子的位置价值
		short piece = this->board[i];
		if (piece / 10 == side) continue;

		const int(*positionValue)[10][9] = NULL;
		//如果是炮
		if (piece == R_CANNON || piece == B_CANNON)
		{
			totalValue += 45;
			positionValue = &cannonPositionValue;
		}
		//如果是車...以此类推
		else if (piece == R_CAR || piece == B_CAR)
		{
			totalValue += 90;
			positionValue = &carPositionValue;
		}
		else if (piece == R_ELEPHANT || piece == B_ELEPHANT)
		{
			totalValue += 20;
			positionValue = &elephantPositionValue;
		}
		else if (piece == R_GUARD || piece == B_GUARD)
		{
			totalValue += 20;
			positionValue = &guardPositionValue;
		}
		else if (piece == R_HORSE || piece == B_HORSE)
		{
			totalValue += 40;
			positionValue = &horsePositionValue;
		}
		else if (piece == R_KING || piece == B_KING)
		{
			totalValue += 1000;
			positionValue = &kingPositionValue;
		}
		else if (piece == R_SOLDIER || piece == B_SOLDIER)
		{
			totalValue += 10;
			positionValue = &soldierPositionValue;
		}
		totalValue += (*positionValue)[((int)!side) * 9 + (2 * ((int)side) - 1) * getY(i)][getX(i)];
	}
	return totalValue;
}


int minMaxSearch(Chess* chess, bool minOrMax, int boundary, bool side, short deep, int& move)
{
	//如果是极大层就把结果先置最小，如果是极小层就先置最大。
	int result = 200000;
	if (minOrMax) result = -200000;

	int tempValue = 0;


	//如果深度是5就直接返回这一个棋盘执子玩家的价值-对面的价值
	if (deep == 5) return chess->getTotalValue(side) - chess->getTotalValue(!side);

	//bug在这里，side永远是不变的。。。
	Stack_list<int,250> tempValidMoves = chess->getValidMoves(chess->getNowPlayer());


	//遍历每一种走法
	for (int i = 0; i < tempValidMoves.size() ;i++)
	{
		//先这样走一步
		chess->move(tempValidMoves.geti(i));
		int tempMove;
		//如果有任意一方将帅没有了，那就如果是己方的就价值就-10000，对方的就10000，并且不会继续加深搜索了。
		if (chess->getKingState() == RB_KING_ALL_HAVE)
		{
			tempValue = minMaxSearch(chess, !minOrMax, result, side, deep + 1, tempMove);
		}
		else if ((side && (chess->getKingState() == NO_B_KING)) 
			|| (!side && (chess->getKingState() == NO_R_KING)))
			tempValue = 100000 - 100 * deep; //同样是对方帅死越快分越高，让电脑尽快吃帅。
		else if ((side && chess->getKingState() == NO_R_KING)
			|| (!side && chess->getKingState() == NO_B_KING)) 
			tempValue = -100000 + 100 * deep;//同样是自己帅死越深层分数越高，让电脑再挣扎一下。



		//之后再挪回来
		chess->rollBack();

		//如果不是是极大层且这么走出来的价值比result大或者极小层且价值这么走价值最小
		//if (!((minOrMax && tempValue > result) || (!minOrMax && tempValue < result)))
		if ((!minOrMax || tempValue <= result) && (minOrMax || tempValue >= result)) continue;
		//把result变成这个数，把走法换成这个走法
		result = tempValue;
		move = tempValidMoves.geti(i);

		//如果父节点是极大层，且目前此搜索结果比父节点的结果要小的话那就不用再搜了。反过来也同理
		if ((!minOrMax && result <= boundary) || (minOrMax && result >= boundary)) return result;

	}

	return result;
}


bool isValidRKingRGuardPosition(int index)
{
	return getX(index) >= 3 && getY(index) >= 7 && getX(index) <= 5 && getY(index) <= 9 && index >= 0 && index <= 129;
}

bool isValidRELEPHANTPosition(int index)
{
	return getX(index) >= 0 && getY(index) >= 5 && getX(index) <= 8 && getY(index) <= 9 && index >= 0 && index <= 129;
}

bool isValidBKingBGuardPosition(int index)
{
	return getX(index) >= 3 && getY(index) >= 0 && getX(index) <= 5 && getY(index) <= 2 && index >= 0 && index <= 129;
}
bool isValidBELEPHANTPosition(int index)
{
	return getX(index) >= 0 && getY(index) >= 0 && getX(index) <= 8 && getY(index) <= 4 && index >= 0 && index <= 129;
}
bool isInBoard(int index)
{
	return (index) >= 0 && (index) <= 129 && getX(index) >= 0 && getX(index) <= 8;
}